package com.voja.salonschedule;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;

import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdSize;
import com.google.android.gms.ads.AdView;
import com.voja.AndroidUtils.Application;
import com.voja.salonschedule.ads.MyAdListener;
import com.voja.salonschedule.data.Customer;
import com.voja.salonschedule.data.Customer.CustomerItem;
import com.voja.salonschedule.data.Event;
import com.voja.salonschedule.data.Event.EventItem;
import com.voja.salonschedule.dialog.EventDialogFragment;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.Dialog;
import android.app.Service;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.ActionBarActivity;
import android.util.Pair;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.DatePicker;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

public class Index extends ActionBarActivity implements OnTouchListener {
	
	public static final String PREF_NAME = "coma.voja.salonschedule";
	public static final String DIAL_PREFIX = "tel:";
	public static final String SMS_PREFIX = "sms:";
	
	public static final int FONT_BOLD   = 601;
	public static final int FONT_ITALIC = 602;
	
	public static int ITEM_HEIGHT = 50;
	public static int ITEM_WIDTH  = 200;
	
	Date date;
	Typeface font, fontB, fontI;
	public static Context context;
	
	LayoutInflater inflater;
	
	SharedPreferences prefs;
	int eventId=0;
	
	public Event    modelEvent;
	public Customer modelCustomer;
	
	int workStart, workEnd, workStep;
	public static Resources res;
	
	public static boolean pressed = false;
	public static ArrayList<String> axis_x = new ArrayList<String>();
	
	// ads
	public static AdView       adView;
	public static MyAdListener adListener;
	public static AdRequest    adRequest;
	
	private int orientation;
	
	private long backTimestamp = 0;
	private int backExitTimeout = 3000;
	
	public static class DatePickerFragment extends DialogFragment
										   implements DatePickerDialog.OnDateSetListener{
		
		private Index getIndex() {
			return (Index)getActivity();
		}
		
		@Override
		public Dialog onCreateDialog(Bundle savedInstance) {
			Date d = getIndex().date;
			
			int year = 1900+d.getYear();
			int month = d.getMonth();
			int day = d.getDate();
			
			return new DatePickerDialog(getActivity(), this, year, month, day);			
		}
		
		public void onDateSet(DatePicker view, int year, int month, int day) {
			month = month+1;
			
			String d = year + "-" + (month>9 ? month : "0"+month) + "-" + (day>9 ? day : "0"+day);
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
			try {
				getIndex().show(sdf.parse(d));
			} catch (ParseException e) {
				Application.alert(res.getString(R.string.msgInvalidDateFormat));
			}
		}
	}
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		context = getApplicationContext();
		Application.setContext(this);
		font  = Typeface.createFromAsset(getAssets(), "font.otf");
		fontB = Typeface.createFromAsset(getAssets(), "fontB.otf");
		fontI = Typeface.createFromAsset(getAssets(), "fontI.otf");
		
		inflater = (LayoutInflater)getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
		res = getResources();
		loadPrefs();
		
		setContentView(R.layout.index);
		
		date          = Calendar.getInstance().getTime();
        modelEvent    = new Event(this);
        modelCustomer = new Customer(this);
	}
	
	public static void initAd(Activity activity) {
		// locate ad container
	    LinearLayout adContainer = (LinearLayout)activity.findViewById(R.id.adContainer);
	    if (adContainer == null) return;
	    
	    // is it already there?
	    View av = adContainer.findViewById(R.string.adView);
	    if (av != null) return;
	    
		// AdView
		adView = new AdView(activity);
		adView.setId(R.string.adView);
		adView.setAdSize(AdSize.SMART_BANNER);
		adView.setAdUnitId(res.getString(R.string.admob_id));		
		adContainer.addView(adView);
		
		// AdListener
		adListener = new MyAdListener(activity, adView);
		adView.setAdListener(adListener);
		
		// AdRequest
		AdRequest.Builder builder = new AdRequest.Builder();
		
		String[] keywords = res.getStringArray(R.array.ad_keywords);
		for (int i=0; i<keywords.length; i++) {
			builder.addKeyword(keywords[i]);
		}
		builder.addTestDevice(AdRequest.DEVICE_ID_EMULATOR);
		adRequest = builder.build();
		adView.loadAd(adRequest);
	}
	
	public boolean validateSettings() {
		String services = prefs.getString(Settings.SERVICES_KEY, Settings.SERVICES_DEFAULT).trim();
		return services != Settings.SERVICES_DEFAULT;
	}
	
	@Override
	public void onResume() {
		super.onResume();
		
		loadPrefs();
		
		findViewById(R.id.scrollContainer).setOnTouchListener(this);
        initAd(this);
        
        drawTimeItems();
        show(date);
        getSupportActionBar().setHomeButtonEnabled(true);
        
        orientation = getResources().getConfiguration().orientation;
        // if landscape load menu into left content view
		if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
		    new LandscapeMenuAdapter(this, R.layout.landscape_menu);
        }
        
        // update widgets
		Widget.context = this;
		Widget.updateWidgets();
	}
	
	@Override
	public void onPause() {
		super.onPause();
	}
	
	@Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        super.onCreateContextMenu(menu, v, menuInfo);
        
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.context, menu);
        eventId = v.getId();
    }
    
    @Override
    public boolean onContextItemSelected(MenuItem item) {
        ArrayList<Pair<String,String>> params = new ArrayList<Pair<String,String>>();
        params.add(Pair.create("id", ""+eventId));
        
        switch (item.getItemId()) {
            case R.id.mnuEdit:
                launch(Events.class, "edit", params);
                return true;
            case R.id.mnuDelete:
                launch(Events.class, "delete", params);
                return true;
            default:
                return super.onContextItemSelected(item);
        }
    }
    
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
            menu.setGroupVisible(R.id.groupOther, false);
        }
        return super.onPrepareOptionsMenu(menu);
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.index, menu);
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case android.R.id.home:
            DialogFragment newFragment = new DatePickerFragment();
            newFragment.show(getSupportFragmentManager(), "datePicker");
            break;
            
        case R.id.menuExit:
            finish();
            return true;
            
        case R.id.menuServices:
        	Intent intent = new Intent(this, Services.class);
        	startActivity(intent);
        	return true;
            
        case R.id.menuCustomers:
            launch(Customers.class);
            return true;
            
        case R.id.menuSettings:
            launch(Settings.class);
            return true;
            
        case R.id.menuPrevDate:
            goTo(-1);
            break;
            
        case R.id.menuNextDate:
            goTo(1);
            break;
        }
        
        return super.onOptionsItemSelected(item);
    }
    
    @Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
    	if (keyCode == KeyEvent.KEYCODE_BACK) {
    		boolean ret = true;
    		long now = Calendar.getInstance().getTimeInMillis();
	    	if ((now - backTimestamp) < backExitTimeout) {
	    		finish();
	    		ret = true;
	    	} else {
	    		Toast.makeText(this, getResources().getString(R.string.exitConfirm), Toast.LENGTH_LONG)
	    			.show();
	    	}
	    	backTimestamp = now;
	    	return ret;
    	} else {
    		return super.onKeyUp(keyCode, event);
    	}
    }
	
	public void loadPrefs() {
		prefs = PreferenceManager.getDefaultSharedPreferences(context);
		
		workStart 	= Integer.parseInt(prefs.getString(Settings.WORK_HOURS_START_KEY, 	Settings.WORK_HOURS_DEFAULT_START));
		workEnd   	= Integer.parseInt(prefs.getString(Settings.WORK_HOURS_END_KEY, 	Settings.WORK_HOURS_DEFAULT_END));
		workStep 	= Integer.parseInt(prefs.getString(Settings.TIME_STEP_KEY, 			Settings.TIME_STEP_DEFAULT));
	}
	
	public void goTo(int days) {
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		c.add(Calendar.DATE, days);
		
		ScrollView sv = (ScrollView)findViewById(R.id.scrollContainer);
		
		sv.setVisibility(View.GONE);
		show(c.getTime());
		sv.setVisibility(View.VISIBLE);
	}
	
	public void show(Date date) {
		this.date = date;
		
		listEvents();
		
		setTitle(Event.dateFormat3.format(date));
	}
	
	public void drawTimeItems() {
		LinearLayout times = (LinearLayout)findViewById(R.id.times);
		times.removeAllViews();
		
		View row;
		TextView time;
		ImageView add;
		String txtTime;
		
		LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
		for (int i=workStart; i<workEnd; i++) {
			for (int j=0; j<60; j+=workStep) {
				row = inflater.inflate(R.layout.time_item, null);
				row.setId(i*60+j);
				row.setLayoutParams(params);
				
				time = (TextView)row.findViewById(R.id.time);
				setFont(time);
				if (j>0) {
					time.setTextColor(Color.parseColor("#22000000"));
				} else {
					time.setTextColor(Color.parseColor("#99000000"));
				}
				
				txtTime = (i>9 ? i : "0"+i) + ":" + (j>9 ? j : "0"+j);
				time.setText(txtTime);
				
				add = (ImageView)row.findViewById(R.id.imgAdd);
				add.setContentDescription(txtTime);
				add.setOnClickListener(new View.OnClickListener() {
					@Override
					public void onClick(View v) {
						SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
						String d = sdf.format(date);
						String h = v.getContentDescription().toString();
						
						ArrayList<Pair<String, String>> params = new ArrayList<Pair<String,String>>();
						params.add(Pair.create("date", d));
						params.add(Pair.create("time", h));
						launch(Events.class, "add", params);
					}
				});
				
				times.addView(row);
			}
		}
		
		View v = times.findViewById(workStart*60);
		if (v != null) {
			v.measure(0, 0);
			ITEM_HEIGHT = v.getMeasuredHeight();
		}
	}
	
	@SuppressLint("InflateParams")
    public void listEvents() {
		RelativeLayout listEvents = (RelativeLayout)findViewById(R.id.events);
		listEvents.removeAllViews();
		
		ArrayList<EventItem> events = modelEvent.loadEvents(date, true, "`date` ASC, `date_end` ASC");
		
		// create events
		RelativeLayout.LayoutParams params;
		
		HashMap<String, Integer> timeCounts = new HashMap<String, Integer>();
		String tmpTime;
		int count;
		
		// Count number of events per appointment
		for (EventItem event1 : events) {
		    count = 1;
		    tmpTime = Event.timeFormat.format(event1.date_start);
		    
		    if (timeCounts.containsKey(tmpTime)) {
		        count = timeCounts.get(tmpTime) + 1;
		    }
	        
		    timeCounts.put(tmpTime, count);
		}
		
		// Draw events
		SimpleDateFormat timeFormat = Event.timeFormat;
		int startMins = time2min(workStart+":00");
		HashMap<String, ArrayList<View>> stack = new HashMap<String, ArrayList<View>>();
		for (EventItem event : events) {
		    
			View v = inflater.inflate(R.layout.event, null);
			v.setId(event.id);
			
			ImageView ivCustomer = (ImageView)v.findViewById(R.id.imgCustomer);
			TextView  tvCustomer = (TextView)v.findViewById(R.id.txtCustomer);
			TextView  tvService  = (TextView)v.findViewById(R.id.txtService);
			setFont(tvCustomer);
			setFont(tvService);
			
			Customer customerModel = new Customer(context);
			CustomerItem customer  = customerModel.getCustomer(event.customer);
			if (customer != null && customer.image != null && customer.image.length>0) {
			    Bitmap bm = BitmapFactory.decodeByteArray(customer.image, 0, customer.image.length);
			    ivCustomer.setImageBitmap(bm);
			}
			tvCustomer.setText(event.customer);
			tvService.setText(event.service);
			
			v.setOnClickListener(new View.OnClickListener() {
				@Override
				public void onClick(View v) {
					int id = v.getId();
					showEvent(id);
				}
			});
			
			registerForContextMenu(v);
			
			// calculate top position
			String time   = Event.timeFormat.format(event.date_start);
			int eventMins = time2min(time) - startMins;
			
			// original params
			RelativeLayout.LayoutParams params0 = (RelativeLayout.LayoutParams)v.getLayoutParams();
			int leftMargin   = 0;
            int rightMargin  = 0;
            int bottomMargin = 5;
			if (params0 != null) {
    			leftMargin   = params0.leftMargin;
    			rightMargin  = params0.rightMargin;
    			bottomMargin = params0.bottomMargin;
			}
			
			int y = eventMins / workStep * ITEM_HEIGHT;
			
			String timeStart = timeFormat.format(event.date_start);
			String timeEnd   = timeFormat.format(event.date_end);
			int minStart = Index.time2min(timeStart);
			int minEnd   = Index.time2min(timeEnd);
			int numAppointments = (minEnd-minStart)/workStep;
			if (numAppointments < 1) {
				numAppointments = 1;
			}

			params = new RelativeLayout.LayoutParams(ITEM_WIDTH, ITEM_HEIGHT * numAppointments);
			params.setMargins(leftMargin, y, rightMargin, bottomMargin);
			
			ArrayList<View> views = stack.get(time);
			if (views != null && views.size()>0) {
			    View last = views.get(views.size()-1);
			    params.addRule(RelativeLayout.RIGHT_OF, last.getId());
			}
			
			listEvents.addView(v, params);
			
			//put view on stack
			if (! stack.containsKey(time)) {
			    stack.put(time, new ArrayList<View>());
			}
			stack.get(time).add(v);
		}
	}
	
	public void showEvent(int id) {
	    EventDialogFragment dialog = new EventDialogFragment();
	    EventItem    event    = modelEvent.findById(id);
	    CustomerItem customer = modelCustomer.getCustomer(event.customer);
        if (customer == null) {
            customer = new CustomerItem();
        }
        dialog.setData(this, event, customer);
        dialog.show(getSupportFragmentManager(), "EventShow");
	}
	
	public static void makeCall(Context context, String phoneNumber) {
	    try {
            Intent i = new Intent(Intent.ACTION_DIAL);
            i.setData(Uri.parse(DIAL_PREFIX + phoneNumber));
            context.startActivity(i);
        } catch (ActivityNotFoundException e) {
            String message = context.getResources().getString(R.string.callingUnavailable);
            Application.alert(message);
        }
	}
	
	public static void sendMessage(Context context, String phoneNumber) {
		try {
			Uri uri = Uri.fromParts("sms", phoneNumber, null);
			Intent i = new Intent(Intent.ACTION_VIEW, uri);
			context.startActivity(i);
        } catch (ActivityNotFoundException e) {
            String message = context.getResources().getString(R.string.callingUnavailable);
            Application.alert(message);
        }
	}
	
	public void launch(Class<?> cls) {
		launch(cls, "index");
	}
	public void launch(Class<?> cls, String action) {
		launch(cls, action, null);
	}
	public void launch(Class<?> cls, String action, ArrayList<Pair<String, String>> params) {
		Intent intent = new Intent(this, cls);
		intent.putExtra("action", action);
		
		if (params != null) {
			for (int i=0; i<params.size(); i++) {
				intent.putExtra(params.get(i).first, params.get(i).second);
			}
		}
		
		startActivityForResult(intent, RESULT_OK);
	}
	
	@Override
	protected void onActivityResult(int reqCode, int resCode, Intent data) {
		switch(resCode) {
			case RESULT_CANCELED:
				finish();
				break;
		}
	}
	
	public void setFont(TextView tv) {
		setFont(tv, 0);
	}
	public void setFont(TextView tv, int mod) {
		switch(mod) {
			case FONT_BOLD:
				tv.setTypeface(fontB);
				break;
			case FONT_ITALIC:
				tv.setTypeface(fontI);
				break;
			default:
				tv.setTypeface(font);
		}
	}
	
	public static int time2min(String time) {
		int mins = 0, h=0, m=0;
		
		if (time.matches("\\d+:\\d+")) {
			String[] tmp = time.split(":", 2);
			h = Integer.parseInt(tmp[0]);
			m = Integer.parseInt(tmp[1]);
			
			mins = h*60 + m;
		}
		
		return mins;
	}
	public static String min2time(int min) {
		int h = (int)Math.floor(min/60);
		int m = min % 60;
		
		return (h>9 ? h : "0"+h)+":"+(m>9 ? m : "0"+m);
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		
		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				pressed = true;
				axis_x = new ArrayList<String>();
				break;
				
			case MotionEvent.ACTION_MOVE:
				if (pressed) {
					axis_x.add(""+event.getX());
				}
				break;
				
			case MotionEvent.ACTION_UP:
				pressed = false;
				
				if (axis_x.size() > 0) {
					float first = Float.parseFloat(axis_x.get(0));
					float last  = Float.parseFloat(axis_x.get(axis_x.size()-1));
					float diff  = last - first;
					
					if(Math.abs(diff) > 200) {
						if (diff > 0) {
							goTo(-1);
						} else {
							goTo(1);
						}
					}
					
				}
				break;
		}
		return false;
	}
}
